#!/bin/bash

#######################
# 0. auth:RuanYuGuang #
#######################

###################
# 1. 变量定义部分 #
###################

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
NC='\033[0m'

# 系统配置
HTTPD_CONF="/etc/httpd/conf.d/project.conf"
PHP_INI="/etc/php.ini"
LOG_FILE="/var/log/game_platform_deploy.log"
BACKUP_DIR="/var/backup/game_platform"

# 数据库配置
DB_NAME="user1"
DB_USER="user1"
DB_PASS="123456"
ROOT_PASS="your_root_password"

# 项目配置
PROJECT_PATH="/var/www/html"
SQL_FILE="user1_2024-12-23_20-28-15_mysql_data_bTSJu.sql"
REPO_URL="https://gitee.com/ruan-yuguang/game-platform.git"

# PHP配置项
PHP_CONFIGS=(
    "date.timezone=Asia/Shanghai"
    "display_errors=Off"
    "max_execution_time=300"
    "max_input_time=300"
    "memory_limit=256M"
    "post_max_size=50M"
    "upload_max_filesize=50M"
    "short_open_tag=On"
)

###################
# 2. 函数定义部分 #
###################

# 基础工具函数
log_message() {
    local level=$1
    local message=$2
    local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
    echo -e "${timestamp} [${level}] ${message}" >> "${LOG_FILE}"
}

handle_error() {
    local error_message=$1
    local line_number=$2
    local stack_trace=$(caller)
    log_message "ERROR" "在第 ${line_number} 行发生错误: ${error_message}"
    log_message "DEBUG" "堆栈跟踪: ${stack_trace}"
    echo -e "${RED}错误: ${error_message}${NC}"
    echo -e "${RED}查看详细日志: ${LOG_FILE}${NC}"
    
    read -p "是否要回滚部署？[y/N] " should_rollback
    if [[ $should_rollback =~ ^[Yy]$ ]]; then
        rollback
    fi
    exit 1
}

show_progress() {
    local step=$1
    local total=$2
    local message=$3
    echo -e "${GREEN}[$step/$total] $message...${NC}"
}

# 备份和恢复函数
backup() {
    local timestamp=$(date +%Y%m%d_%H%M%S)
    if [ -f "$1" ]; then
        cp "$1" "$1.bak_${timestamp}"
        echo -e "${GREEN}已备份 $1 到 $1.bak_${timestamp}${NC}"
    fi
}

backup_all() {
    echo -e "${GREEN}开始备份...${NC}"
    log_message "INFO" "开始备份操作"
    mkdir -p "${BACKUP_DIR}"

    if [ -d ${PROJECT_PATH} ]; then
        cp -r ${PROJECT_PATH} "${BACKUP_DIR}/html_backup"
        log_message "INFO" "网站文件备份成功"
    fi

    if [ -f ${HTTPD_CONF} ]; then
        cp ${HTTPD_CONF} "${BACKUP_DIR}/project.conf.bak"
        log_message "INFO" "Apache配置备份成功"
    fi
}

rollback() {
    echo -e "${GREEN}开始回滚...${NC}"
    log_message "INFO" "开始回滚操作"

    if [ -d "${BACKUP_DIR}/html_backup" ]; then
        rm -rf ${PROJECT_PATH}
        cp -r "${BACKUP_DIR}/html_backup" ${PROJECT_PATH}
    fi

    if [ -f "${BACKUP_DIR}/project.conf.bak" ]; then
        cp "${BACKUP_DIR}/project.conf.bak" ${HTTPD_CONF}
    fi

    log_message "INFO" "回滚操作完成"
    echo -e "${GREEN}回滚完成${NC}"
}

# 安装和配置函数
check_dependencies() {
    local missing_deps=()
    local install_deps=()
    
    # 检查必要的命令
    for cmd in git mysql mysqldump wget curl; do
        if ! command -v $cmd &> /dev/null; then
            case $cmd in
                git)
                    install_deps+=("git")
                    ;;
                mysql|mysqldump)
                    install_deps+=("mariadb" "mariadb-server")
                    ;;
                wget)
                    install_deps+=("wget")
                    ;;
                curl)
                    install_deps+=("curl")
                    ;;
            esac
            missing_deps+=("$cmd")
        fi
    done

    if [ ${#missing_deps[@]} -ne 0 ]; then
        echo -e "${GREEN}正在安装缺失的依赖: ${missing_deps[*]}${NC}"
        log_message "INFO" "安装缺失的依赖: ${missing_deps[*]}"
        
        # 更新包管理器缓存
        dnf clean all
        dnf makecache
        
        # 安装缺失的包
        if ! dnf install -y "${install_deps[@]}"; then
            handle_error "无法安装依赖包: ${install_deps[*]}" $LINENO
        fi
        
        # 如果安装了数据库，需要启动服务
        if [[ " ${install_deps[@]} " =~ " mariadb-server " ]]; then
            manage_service start mariadb
            manage_service enable mariadb
        fi
        
        # 再次检查是否所有依赖都已安装
        local still_missing=()
        for cmd in "${missing_deps[@]}"; do
            if ! command -v $cmd &> /dev/null; then
                still_missing+=("$cmd")
            fi
        done
        
        if [ ${#still_missing[@]} -ne 0 ]; then
            handle_error "以下依赖安装失败: ${still_missing[*]}" $LINENO
        fi
        
        echo -e "${GREEN}所有依赖安装完成${NC}"
        log_message "INFO" "所有依赖安装完成"
    fi
}

configure_php() {
    for config in "${PHP_CONFIGS[@]}"; do
        key="${config%%=*}"
        value="${config#*=}"
        sed -i "s|^;*\s*${key}\s*=.*|${key} = ${value}|" $PHP_INI
    done
}

manage_service() {
    local action=$1
    local service=$2
    if ! systemctl $action $service; then
        handle_error "${service} ${action} 失败" $LINENO
    fi
}

# 验证函数
validate_configs() {
    if [[ ! -d "$(dirname $BACKUP_DIR)" ]]; then
        mkdir -p "$(dirname $BACKUP_DIR)"
    fi
}

verify_deployment() {
    local errors=0
    
    if ! curl -s "http://${DOMAIN}" > /dev/null; then
        log_message "ERROR" "网站无法访问"
        errors=$((errors + 1))
    fi
    
    if ! mysql -u ${DB_USER} -p${DB_PASS} ${DB_NAME} -e "SELECT 1" > /dev/null 2>&1; then
        log_message "ERROR" "数据库连接失败"
        errors=$((errors + 1))
    fi
    
    if [ ! -w "${PROJECT_PATH}/data/img" ]; then
        log_message "ERROR" "上传目录权限不正确"
        errors=$((errors + 1))
    fi
    
    if [ $errors -gt 0 ]; then
        handle_error "部署验证失败，发现 ${errors} 个错误" $LINENO
    fi
}

cleanup() {
    if [ -d "${PROJECT_PATH}.bak" ]; then
        rm -rf "${PROJECT_PATH}.bak"
    fi
}

#########################
# 3. 错误处理和trap设置 #
#########################

set -e
trap 'handle_error "第 $LINENO 行发生错误"' ERR
trap cleanup EXIT

###################
# 4. 主程序部分  #
###################

main() {
    # 初始化检查
    if [ "$EUID" -ne 0 ]; then 
        echo -e "${RED}请使用root权限运行此脚本${NC}"
        exit 1
    fi

    echo -e "${GREEN}开始部署游戏平台...${NC}"
    log_message "INFO" "开始部署游戏平台"

    # 准备工作
    validate_configs
    check_dependencies
    touch "${LOG_FILE}"
    chmod 644 "${LOG_FILE}"

    # 获取配置信息
    SERVER_IP=$(ip -4 addr show | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | grep -v '127.0.0.1' | head -n 1)
    echo -e "检测到服务器IP: ${SERVER_IP}"
    read -p "请输入网站访问域名/IP [${SERVER_IP}]: " DOMAIN
    DOMAIN=${DOMAIN:-$SERVER_IP}

    # 设置数据库密码
    read -sp "请输入数据库root密码 [your_root_password]: " input_root_pass
    echo
    ROOT_PASS=${input_root_pass:-"your_root_password"}

    # 安装确认
    show_progress 1 12 "确认安装信息"
    echo -e "配置信息如下："
    echo -e "域名/IP: ${DOMAIN}"
    echo -e "数据库名: ${DB_NAME}"
    echo -e "数据库用户: ${DB_USER}"
    echo -e "网站目录: ${PROJECT_PATH}"
    echo -e "数据库root密码: ********"

    read -p "确认安装？[y/N] " confirm
    if [[ ! $confirm =~ ^[Yy]$ ]]; then
        echo "安装已取消"
        exit 0
    fi

    # 开始安装
    show_progress 2 12 "备份系统"
    backup_all

    show_progress 3 12 "安装基础软件包"
    dnf install -y epel-release
    dnf install -y httpd php php-cli php-fpm php-mysqlnd php-json php-gd php-mbstring mariadb mariadb-server

    show_progress 4 12 "克隆项目代码"
    [ -d ${PROJECT_PATH} ] && mv ${PROJECT_PATH} ${PROJECT_PATH}.bak
    git clone ${REPO_URL} ${PROJECT_PATH}

    show_progress 5 12 "配置数据库"
    # 确保数据库服务正在运行
    if ! systemctl is-active --quiet mariadb; then
        echo -e "${GREEN}启动数据库服务...${NC}"
        if ! systemctl start mariadb; then
            handle_error "无法启动数据库服务" $LINENO
        fi
    fi

    # 等待数据库完全启动
    max_attempts=30
    attempt=1
    while ! mysqladmin ping -s > /dev/null 2>&1; do
        if [ $attempt -ge $max_attempts ]; then
            handle_error "等待数据库启动超时" $LINENO
        fi
        echo -e "${GREEN}等待数据库启动... (${attempt}/${max_attempts})${NC}"
        sleep 1
        ((attempt++))
    done

    echo -e "${GREEN}数据库服务已启动${NC}"
    log_message "INFO" "数据库服务已启动并正常运行"
    mysql -u root <<EOF
    ALTER USER 'root'@'localhost' IDENTIFIED BY '${ROOT_PASS}';
    DELETE FROM mysql.user WHERE User='';
    DELETE FROM mysql.user WHERE User='root' AND Host NOT IN ('localhost', '127.0.0.1', '::1');
    DROP DATABASE IF EXISTS test;
    DELETE FROM mysql.db WHERE Db='test' OR Db='test\\_%';
    CREATE DATABASE ${DB_NAME};
    CREATE USER '${DB_USER}'@'localhost' IDENTIFIED BY '${DB_PASS}';
    GRANT ALL PRIVILEGES ON ${DB_NAME}.* TO '${DB_USER}'@'localhost';
    FLUSH PRIVILEGES;
EOF

    show_progress 6 12 "导入数据库"
    if [ ! -f "${PROJECT_PATH}/${SQL_FILE}" ]; then
        handle_error "找不到数据库导入文件: ${SQL_FILE}" $LINENO
    fi
    mysql -u ${DB_USER} -p${DB_PASS} ${DB_NAME} < "${PROJECT_PATH}/${SQL_FILE}"

    show_progress 7 12 "配置Apache"
    backup ${HTTPD_CONF}
    cat > ${HTTPD_CONF} <<EOF
<VirtualHost *:80>
    ServerName ${DOMAIN}
    DocumentRoot "${PROJECT_PATH}"
    DirectoryIndex index.php index.html
    
    <Directory "${PROJECT_PATH}">
        Options Indexes FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>

    AddType application/x-httpd-php .php
    AddDefaultCharset UTF-8
    
    ErrorLog /var/log/httpd/error.log
    CustomLog /var/log/httpd/access.log combined
</VirtualHost>
EOF

    show_progress 8 12 "配置PHP"
    configure_php

    show_progress 9 12 "创建必要目录"
    mkdir -p ${PROJECT_PATH}/data/img
    mkdir -p ${PROJECT_PATH}/data/game
    chown -R apache:apache ${PROJECT_PATH}
    chmod -R 755 ${PROJECT_PATH}
    chmod -R 777 ${PROJECT_PATH}/data/img

    show_progress 10 12 "配置SELinux"
    setsebool -P httpd_can_network_connect 1
    chcon -R -t httpd_sys_rw_content_t ${PROJECT_PATH}/data/img
    
    show_progress 11 12 "配置防火墙"
    # 检查防火墙是否运行
    if systemctl is-active --quiet firewalld; then
        # 开放 HTTP 和 HTTPS 端口
        firewall-cmd --permanent --add-service=http
        firewall-cmd --permanent --add-service=https
        # 重新加载防火墙配置
        firewall-cmd --reload
        echo -e "${GREEN}防火墙配置已更新${NC}"
    else
        echo -e "${GREEN}防火墙未运行，跳过配置${NC}"
    fi

    # 检查并禁用SELinux（可选）
    if [ -f "/etc/selinux/config" ]; then
        sed -i 's/^SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config
        echo -e "${GREEN}SELinux已设置为禁用，重启后生效${NC}"
        # 临时禁用SELinux
        setenforce 0
    fi

    show_progress 12 12 "启动服务"
    manage_service restart httpd
    manage_service enable httpd
    manage_service restart php-fpm
    manage_service enable php-fpm
    manage_service restart mariadb
    manage_service enable mariadb

    show_progress 13 13 "验证部署"
    verify_deployment

    echo -e "${GREEN}部署完成！${NC}"
    echo -e "${GREEN}注意事项：${NC}"
    echo -e "1. 如果使用域名访问，请确保已经正确设置DNS解析"
    echo -e "2. 如果无法访问，请检查以下几点："
    echo -e "   - 确保服务器防火墙已开放80端口"
    echo -e "   - 确保云服务器安全组已开放80端口"
    echo -e "   - 尝试使用 curl http://localhost 测试本地访问"
    echo -e "3. SELinux已设置为禁用，建议重启服务器使配置生效"
    echo -e "${GREEN}请访问以下地址：${NC}"
    echo -e "${GREEN}前台地址：http://${DOMAIN}${NC}"
    echo -e "${GREEN}后台地址：http://${DOMAIN}/admin${NC}"
    echo -e "${GREEN}数据库信息：${NC}"
    echo -e "数据库名：${DB_NAME}"
    echo -e "用户名：${DB_USER}"
    echo -e "密码：${DB_PASS}"
    log_message "INFO" "部署完成"
}

# 执行主程序
main 